package redislock

import (
	"context"
	"time"

	"github.com/redis/go-redis/v9"
)

var ctx = context.Background()

// RedisLock represents a distributed lock
type RedisLock struct {
	client     *redis.Client
	key        string
	value      string
	expiry     time.Duration
	maxRetries int
}

// NewRedisLock creates a new RedisLock
func NewRedisLock(
	client *redis.Client, key string, value string, expiry time.Duration,
) *RedisLock {
	return &RedisLock{
		client:     client,
		key:        key,
		value:      value,
		expiry:     expiry,
		maxRetries: 3,
	}
}

// Acquire attempts to acquire the lock
func (lock *RedisLock) Acquire() (bool, error) {
	for i := 0; i < lock.maxRetries; i++ {
		success, err := lock.client.SetNX(ctx, lock.key, lock.value, lock.expiry).Result()
		if err != nil {
			return false, err
		}
		if success {
			return true, nil
		}
	}
	return false, nil
}

// Release releases the lock
func (lock *RedisLock) Release() (bool, error) {
	// Use a Lua script to ensure the lock is only released if it is held by the same value
	script := `
if redis.call("GET", KEYS[1]) == ARGV[1] then
	return redis.call("DEL", KEYS[1])
else
	return 0
end
`
	result, err := lock.client.Eval(ctx, script, []string{lock.key}, lock.value).Result()
	if err != nil {
		return false, err
	}
	return result.(int64) == 1, nil
}
